package com.eureka.auth.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.eureka.auth.service.AuthService;
import com.eureka.basefeign.user.AdminFeign;
import com.eureka.baseredis.service.RedissonSingleService;
import com.eureka.bclass.base.BaseException;
import com.eureka.bclass.base.BaseLoginUserInfo;
import com.eureka.bclass.base.BaseResult;
import com.eureka.bclass.constant.SysKeyConstant;
import com.eureka.bclass.enums.SysKeyEnum;
import com.eureka.bclass.util.JwtUtil;
import com.eureka.bclass.util.StrUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.text.MessageFormat;

/**
 * @Description: 用户授权服务实现类
 * @Author: lixing
 * @Date: 2021/7/14 20:23
 */
@Service
public class AuthServiceImpl implements AuthService {
    /**
     * @Description JWT startExpires 毫秒后生效
     * @Author lixing
     * @Date 2021/6/30 8:42
     */
    @Value("${jwt.startExpires}")
    private String startExpires;

    /**
     * @Description JWT endExpires 毫秒后过期
     * @Author lixing
     * @Date 2021/6/30 8:43
     */
    @Value("${jwt.endExpires}")
    private String endExpires;

    @Resource
    private AdminFeign adminFeign;

    @Resource
    private RedissonSingleService<String> redissonSingleServiceString;

    /**
     * @Description 登录
     * @Author lixing
     * @Date 2021/6/17 9:11
     * @Param [baseLoginUserInfo]
     * @return com.eureka.bclass.base.BaseResult<java.lang.String>
     */
    @Override
    public BaseResult<JSONObject> login(BaseLoginUserInfo baseLoginUserInfo, HttpServletRequest request) {
        /** 校验参数 */
        String client = baseLoginUserInfo.getClient();
        if (!StrUtil.isEffective(client)) {
            throw new BaseException("未知的客户端");
        }
        String category = baseLoginUserInfo.getCategory();
        if (!StrUtil.isEffective(category)) {
            throw new BaseException("未知的用户类型");
        }
        String loginType = baseLoginUserInfo.getLoginType();
        if (!StrUtil.isEffective(loginType)) {
            throw new BaseException("未知的登录方式");
        }
        String account = baseLoginUserInfo.getAccount();
        if (!StrUtil.isEffective(account)) {
            throw new BaseException("请填写账号");
        }
        String pass = baseLoginUserInfo.getPass();
        if (!StrUtil.isEffective(pass)) {
            throw new BaseException("请填写密码或短信验证码");
        }
        String graphicVerificationCode = baseLoginUserInfo.getGraphicVerificationCode();
        if (!StrUtil.isEffective(graphicVerificationCode)) {
            throw new BaseException("请填写图形验证码");
        }

        /**
         * 根据登录方式校验验证码：
         * 1、账号和密码登录：校验图形验证码，校验成功后查询用户信息返回并校验密码
         * 2、短信验证码登录：校验图形验证码和短信验证码，校验成功后查询用户信息返回
         */
        String graphicVerificationCodeKey = MessageFormat.format(SysKeyEnum.LOGIN_USER_GRAPHICVERIFICATIONCODE.getKey(), SysKeyConstant.PROJECTNAME, null);
        Object graphicVerificationCodeObj = request.getSession().getAttribute(graphicVerificationCodeKey);
        String graphicVerificationCodeValue = null == graphicVerificationCodeObj ? null : graphicVerificationCodeObj.toString();
        if (!graphicVerificationCode.equals(graphicVerificationCodeValue)) {
            //throw new BaseException("图形验证码错误");
        }

        /** 如果是短验证码登录 */
        if (SysKeyEnum.LOGIN_TYPE_SMSCODE.getKey().equals(loginType)) {
            String smsVerificationCodeKey = MessageFormat.format(SysKeyEnum.LOGIN_USER_SMSVERIFICATIONCODE.getKey(), SysKeyConstant.PROJECTNAME, account);
            String smsVerificationCodeValue =  redissonSingleServiceString.getKey(smsVerificationCodeKey);
            if (!pass.equals(smsVerificationCodeValue)) {
                throw new BaseException("短信验证码错误");
            }
        }

        /** 登录用户类型 */
        BaseLoginUserInfo baseLoginUserInfoResult;
        if (SysKeyEnum.LOGIN_CATEGORY_SYSTEM.getKey().equals(category)) {
            // 系统用户登录
            baseLoginUserInfoResult = adminFeign.login(baseLoginUserInfo);
        } else if (SysKeyEnum.LOGIN_CATEGORY_MEMBER.getKey().equals(category)) {
            // 会员用户登录
            baseLoginUserInfoResult = adminFeign.login(baseLoginUserInfo);
        } else {
            throw new BaseException("登录用户类型非法");
        }

        /** 如果是账号和密码方式登录，还需要校验密码 */
        if (SysKeyEnum.LOGIN_TYPE_SMSCODE.getKey().equals(loginType)) {
            try {
                // 前台通过公钥加密的密码
                // superAdmin
                // REJkWB2pFbdzrzrtmfdgGxP%2FoNpth1DNLGOxtaWxd6UWl0XBpyDjcAWLUnudyZwtz2GcD99r3gv4j7kNyxIdNIKApuc5Jk42VRbWZCzXSrl0go1DiwucQvwaiE0jV49Hb0d9STs554GDxKG128TVemyaA4xTNu9Vjd1udFO5EQI%3D
                if (!pass.equals(baseLoginUserInfoResult.getPass())) {
                    throw new BaseException("密码错误");
                }
            } catch (Exception e) {
                throw new BaseException("密码校验出错");
            }
        }

        // 登录成功后的信息
        JSONObject loginSuccessObj = new JSONObject();
        loginSuccessObj.put(SysKeyEnum.USERINFO_ACCOUNT.getKey(), baseLoginUserInfoResult.getAccount());
        loginSuccessObj.put(SysKeyEnum.USERINFO_PHONE.getKey(), baseLoginUserInfoResult.getPhone());
        loginSuccessObj.put(SysKeyEnum.USERINFO_VERSION.getKey(), String.valueOf(System.currentTimeMillis()));

        // 在redis中记录用户的登录版本号
        String versionKey = MessageFormat.format(SysKeyEnum.LOGIN_USER_VERSION.getKey(), SysKeyConstant.PROJECTNAME, baseLoginUserInfo.getAccount());
        redissonSingleServiceString.setKey(versionKey, loginSuccessObj.getString(SysKeyEnum.USERINFO_VERSION.getKey()), Long.parseLong(endExpires));
        // 根据登录认证信息和版本号生成token
        JSONObject jwt = new JSONObject();
        jwt.put("startExpires", startExpires);
        jwt.put("endExpires", endExpires);
        jwt.put(SysKeyEnum.USERINFO.getKey(), loginSuccessObj.toJSONString());
        String jwtStr = JwtUtil.createJwtForHs256(jwt);
        //
        JSONObject tokenData = new JSONObject();
        tokenData.put("token", jwtStr);
        return new BaseResult<JSONObject>().success(tokenData);
    }

    /**
     * @Description 获取用户密码
     * @Author lixing
     * @Date 2021/6/19 22:11
     * @Param [baseLoginUserInfo]
     * @return com.eureka.bclass.base.BaseResult<java.lang.String>
     */
    @Override
    public BaseResult<BaseLoginUserInfo> getUserPwd(BaseLoginUserInfo baseLoginUserInfo) {
        String pwd = adminFeign.getUserPwd();
        baseLoginUserInfo.setPass(pwd);
        return new BaseResult<BaseLoginUserInfo>().setData(baseLoginUserInfo);
    }
}
